#pragma once

#include <stdio.h>
#include <stdlib.h>
#include "SpinLock.h"

template <typename T, typename CLock = CFakeLock>
class CLinkedList
{
public:
    struct Node : public T
    {
        friend class CLinkedList;

    protected:
        CLinkedList<T, CLock> *pList;
        Node *next;
        Node *prev;

    public:
        ~Node() {}
        Node *Next() { return next; }
        Node *Prev() { return prev; }
        CLinkedList<T, CLock> *Belong() { return pList; }

    public:
        Node(const Node &rhs) = delete;
        Node &operator=(const Node &rhs) = delete;
        Node &operator=(Node &&rhs) = delete;

    protected:
        Node()
        {
            pList = nullptr;
            next = nullptr;
            prev = nullptr;
        }

    private:
        void *operator new(std::size_t sz) { return malloc(sz); }
        void *operator new(std::size_t sz, int iExt) { return malloc(sz + iExt); }
        void *operator new(std::size_t, void *ptr) _GLIBCXX_USE_NOEXCEPT { return ptr; }
        void operator delete(void *ptr) { free(ptr); }
    };

public:
    CLinkedList()
    {
        m_pHead = nullptr;
        m_pTail = nullptr;
        m_nSize = 0;
    }

    virtual ~CLinkedList()
    {
        Destroy();
    }

    virtual Node *NewNode()
    {
        return new Node();
    }

    virtual Node *NewNode(int iExtLen)
    {
        return new (iExtLen) Node();
    }

    virtual Node *NewNode(void *ptr)
    {
        if (nullptr == ptr)
            return nullptr;

        return new (ptr) Node();
    }

    virtual void DeleteNode(Node *pNode)
    {
        // 自动调用Node及其父结构的析构函数,父结构需虚析构函数
        delete pNode;
    }

    bool PushFront(Node *pNode)
    {
        if (nullptr == pNode)
        {
            printf("Error (nullptr == pNode):\tfile=%s\tline=%d\n", __FILE__, __LINE__);
            return false;
        }

        pNode->pList = this;
        m_lock.lock();

        if (nullptr == m_pHead)
        {
            m_pHead = m_pTail = pNode;
            m_pHead->next = nullptr;
            m_pHead->prev = nullptr;
        }
        else
        {
            pNode->prev = nullptr;
            pNode->next = m_pHead;
            m_pHead->prev = pNode;
            m_pHead = pNode;
        }

        m_nSize++;
        m_lock.unlock();

        return true;
    }

    bool PushBack(Node *pNode)
    {
        if (nullptr == pNode)
        {
            printf("Error (nullptr == pNode):\tfile=%s\tline=%d\n", __FILE__, __LINE__);
            return false;
        }

        pNode->pList = this;
        m_lock.lock();

        if (nullptr == m_pTail)
        {
            m_pHead = m_pTail = pNode;
            m_pTail->next = nullptr;
            m_pTail->prev = nullptr;
        }
        else
        {
            pNode->next = nullptr;
            pNode->prev = m_pTail;
            m_pTail->next = pNode;
            m_pTail = pNode;
        }

        m_nSize++;
        m_lock.unlock();

        return true;
    }

    Node *PopFront()
    {
        Node *pHeader = nullptr;

        m_lock.lock();

        if (nullptr == m_pHead)
        {
            m_lock.unlock();

            printf("Error (nullptr == m_pListHead):\tfile=%s\tline=%d\n", __FILE__, __LINE__);
            return nullptr;
        }

        pHeader = m_pHead;

        if (nullptr == m_pHead->next)
        {
            m_pHead = m_pTail = nullptr;
        }
        else
        {
            m_pHead = m_pHead->next;
            m_pHead->prev = nullptr;
        }

        m_nSize--;
        m_lock.unlock();
        pHeader->next = nullptr;
        pHeader->prev = nullptr;
        pHeader->pList = nullptr;

        return pHeader;
    }

    Node *PopBack()
    {
        Node *pTailer = nullptr;

        m_lock.lock();

        if (nullptr == m_pTail)
        {
            m_lock.unlock();

            printf("Error (nullptr == m_pListTail):\tfile=%s\tline=%d\n", __FILE__, __LINE__);
            return nullptr;
        }

        pTailer = m_pTail;

        if (nullptr == m_pTail->prev)
        {
            m_pHead = m_pTail = nullptr;
        }
        else
        {
            m_pTail = m_pTail->prev;
            m_pTail->next = nullptr;
        }

        m_nSize--;
        m_lock.unlock();
        pTailer->next = nullptr;
        pTailer->prev = nullptr;
        pTailer->pList = nullptr;

        return pTailer;
    }

    bool Remove(Node *pNode)
    {
        if (nullptr == pNode)
        {
            printf("Error (nullptr == pNode):\tfile=%s\tline=%d\n", __FILE__, __LINE__);
            return false;
        }

        m_lock.lock();

        // 数据不为本链表的，则失败
        if (pNode->pList != this)
        {
            m_lock.unlock();
            printf("Error (pNode->pList != this):\tfile=%s\tline=%d\n", __FILE__, __LINE__);
            return false;
        }

        if ((nullptr == m_pHead) || (nullptr == m_pTail))
        {
            m_lock.unlock();
            printf("Error ((nullptr == m_pListHead) || (nullptr == m_pListTail)):\tfile=%s\tline=%d\n", __FILE__, __LINE__);
            return false;
        }

        if (m_pHead == pNode)
        {
            if (nullptr == m_pHead->next)
            {
                m_pHead = m_pTail = nullptr;
            }
            else
            {
                m_pHead = m_pHead->next;
                m_pHead->prev = nullptr;
            }
        }
        else if (m_pTail == pNode)
        {
            if (nullptr == m_pTail->prev)
            {
                m_pHead = m_pTail = nullptr;
            }
            else
            {
                m_pTail = m_pTail->prev;
                m_pTail->next = nullptr;
            }
        }
        else
        {
            pNode->prev->next = pNode->next;
            pNode->next->prev = pNode->prev;
        }

        m_nSize--;
        m_lock.unlock();

        // 清除移除的节点链表指针数据,以防发生意外导致链表数据出错
        pNode->next = nullptr;
        pNode->prev = nullptr;
        pNode->pList = nullptr;

        return true;
    }

    virtual void Destroy()
    {
        Node *pHead = nullptr;

        m_lock.lock();

        while (nullptr != m_pHead)
        {
            pHead = m_pHead;

            if (nullptr == m_pHead->next)
            {
                m_pHead = m_pTail = nullptr;
            }
            else
            {
                m_pHead = m_pHead->next;
                m_pHead->prev = nullptr;
            }

            DeleteNode(pHead);
        }

        m_nSize = 0;
        m_pHead = nullptr;
        m_pTail = nullptr;

        m_lock.unlock();
    }

    Node *GetHeader() { return m_pHead; }
    Node *GetTailer() { return m_pTail; }

    unsigned int GetSize() { return m_nSize; }
    bool IsEmpty() { return (0 == m_nSize); }

protected:
    Node *m_pHead;
    Node *m_pTail;
    unsigned int m_nSize;
    CLock m_lock;
};

template <typename T, typename CLock = CFakeLock>
class CLinkedListEx : public CLinkedList<T, CLock>
{
public:
    CLinkedListEx() { m_pExtData = nullptr; }
    virtual ~CLinkedListEx() {}

    void SetExtData(void *pData) { m_pExtData = pData; }
    void *GetExtData() { return m_pExtData; }

protected:
    void *m_pExtData;
};